﻿using System;
using System.Activities;
using System.Activities.Presentation;
using System.Activities.Presentation.Model;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Headsight.BPMN2WF.BPMN;
using Headsight.BPMN2WF.BPMN.Model;
using Headsight.BPMN2WF.BPMN.Schemas;
using Headsight.BPMN2WF.Testing.TestObjCtors;
using Headsight.BPMN2WF.Transformation;
using Headsight.BPMN2WF.Transformation.BPMN2TransformerMappings.Additions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using BPMNFlowNodesBlockFactory = Headsight.BPMN2WF.BPMN.BPMNFlowNodesBlockFactory;

namespace Headsight.BPMN2WF.Testing
{
    public class BPMN2WFTranformationTester
    {
        private BPMN2WFTransformations4TestingCtor _bpmn2WfTransMappingsCtor;

        public BPMN2WFTranformationTester Create()
        {
            return this;
        }

        public BPMN2WFTranformationTesterResult Transform(BPMNFlowNode bpmnFlowNode)
        {
            IList<BPMNArgument> arguments = new List<BPMNArgument>();
            IList<BPMNFlowNode> bpmnFlowNodes = new List<BPMNFlowNode>();
            IList<BPMNSequenceFlow> bpmnSeqFlows = new List<BPMNSequenceFlow>();

            bpmnFlowNodes.Add(bpmnFlowNode);

            var tProcess = new tProcessCtor().WithId("tProcessId")
                .With(bpmnSeqFlows.Select(x => x.TElement).ToArray())
                .With(bpmnFlowNodes.Select(x => x.TElement).ToArray())
                .Create();
            var tDefinitions = new tDefinitionsCtor().With(tProcess).Create();
            var bpmnProcess = new BPMNFlowNodesBlockFactory().CreateBPMNFlowNodesBlock(tDefinitions);

            var abc = new BPMN2WFTransformationsCacheWrapper(_bpmn2WfTransMappingsCtor.Create());
            var bpmn2Wf = BPMN2WFFactory.Create(abc, false, null);
            var result = bpmn2Wf.Transform(bpmnProcess);

            var activity =
                ((ActivityBuilder)
                 ((WorkflowDesigner)result.Model).Context.Services.GetService<ModelTreeManager>().Root.GetCurrentValue())
                    .Implementation;

            return new BPMN2WFTranformationTesterResult(abc.Cache.FirstOrDefault().Value, activity);
        }

        public BPMN2WFTranformationTester With(BPMN2WFTransformations4TestingCtor bpmn2WfTransMappingsCtor)
        {
            _bpmn2WfTransMappingsCtor = bpmn2WfTransMappingsCtor;

            return this;
        }

        public BPMN2WFTranformationTesterResult Transform(tDefinitions tDefinitions)
        {
            var bpmnDefinitions = new BPMNFlowNodesBlockFactory().CreateBPMNFlowNodesBlock(tDefinitions);

            var bpmn2Wf = BPMN2WFFactory.Create(_bpmn2WfTransMappingsCtor.Create(), false, null);
            var result = bpmn2Wf.Transform(bpmnDefinitions);

            var file = Properties.Settings.Default.TestingRootDir + @"\Headsight.BPMN2WFTest.Workflows\Models\BPMN2WFTransformationTester.xaml";
            ((WorkflowDesigner)result.Model).Save(file);

            var activity =
                ((ActivityBuilder)
                 ((WorkflowDesigner)result.Model).Context.Services.GetService<ModelTreeManager>().Root.GetCurrentValue())
                    .Implementation;
//            XAMLSerializer.Save(_activity, @"I:\Test.xaml");

            return new BPMN2WFTranformationTesterResult(null, activity);
        }
    }

    public class BPMN2WFTranformationTesterResult
    {
        public BPMN2WFTranformationTesterResult(BPMNTransformationResult bpmnTransformationResult, Activity activity)
        {
            BPMNTransformationResult = bpmnTransformationResult;
            Activity = activity;
        }

        public Activity Activity { get; private set; }

        public BPMNTransformationResult BPMNTransformationResult { get; private set; }

        public StringWriter Execute()
        {
            var result = new StringWriter();

            var tmp = Console.Out;

            try
            {
                Console.SetOut(result);
                WorkflowInvoker.Invoke(Activity);
            }
            finally
            {
                Console.SetOut(tmp);
            }

            return result;
        }

    }
}